//
//  GameScene.m
//  iSuDoku
//
//  Created by maccctk on 09-6-23.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import <AudioToolbox/AudioToolbox.h>
#import "GameScene.h"
#import "MenuScene.h"
#import "Question.h"
#import "LevelScene.h"

#define XOFF							26
#define YOFF							24
#define XGAP							33
#define YGAP							33

@implementation GameScene

- (id)init {
	NSLog(@"GameScene init");
	
	self = [super init];
	if(self != nil) {
		Sprite *bg = [Sprite spriteWithFile:@"game.png"];
		[bg setPosition:ccp(240, 160)];
		[self addChild:bg z:0];
		
		Sprite *board = [Sprite spriteWithFile:@"board.png"];
		[board setPosition:ccp(160, 160)];
		[self addChild:board z:0];
		
		Sprite *cmdSprite = [Sprite spriteWithFile:@"cmd.png"];
		[cmdSprite setPosition:ccp(420, 106)];
		[self addChild:cmdSprite z:0];
		
		Sprite *note = [Sprite spriteWithFile:@"note.png"];
		[note setPosition:ccp(350, 202)];
		[self addChild:note z:0];
		
		Sprite *sp = [Sprite spriteWithFile:@"sprite.png"];
		[sp setPosition:ccp(340, 260)];
		[self addChild:sp z:0];
		
		gl = [GameLayer node];
		[self addChild:gl z:0];
	}
	return self;
}

- (void)setLevel:(int)lv {
	NSLog(@"GameScene setLevel = %d", lv);
	
	[gl setLevel:lv];
}

@end

@implementation GameLayer

- (char)get_digit:(int)i {
	if(cur_question == nil)
		return ' ';
	return cur_question[i+1];
}

- (bool)is_alpha_doku {
	if(cur_question == nil)
		return NO;
	int i;
	
	for(i = 0 ; cur_question[i] ; i ++) {
		if(cur_question[i] >= 'a' && cur_question[i] <= 'z')
			return YES;
		if(cur_question[i] >= 'A' && cur_question[i] <= 'Z')
			return YES;
	}
	return NO;
}

- (void)get_digit_xy:(int)n :(int *)x :(int *)y {
	*x = XOFF + (n % 9) * XGAP + (n % 9) / 3;
	*y = YOFF + (8 - n / 9) * YGAP + (8 - n / 9) / 3;
}

- (void)get_keyboard_xy:(int)n :(int *)x :(int *)y {
	*x =  20 + (n % 3) * 40;
	*y =  15 + (3 - n / 3) * 30;
	if(n >= 9)
		*x += 40;
}

- (void)get_cmd_xy:(int)n :(int *)x :(int *)y {
	*x = 0;
	*y = (6 - n) * 30;
}

- (void)initCmd {
	char *cmdList[] = { "next", "prev", "level", "reset", "final", "main", nil };
	int x, y, i;
	
	Menu *menu = [Menu menuWithItems:nil];
	for(i = 0 ; cmdList[i] != nil ; i ++) {
		NSString *str;
		str = [[NSString alloc] initWithFormat:@"%s", cmdList[i]];
		
		citem[i] = [MenuItemFont itemFromString:str target:self selector:@selector(cmdClicked:)];
		Label *label = citem[i].label;
		[label initWithString:str dimensions:CGSizeMake(60,20) alignment:UITextAlignmentLeft fontName:@"Helvetica" fontSize:11];
		[label setRGB:0 :0 :0x80];				
		
		[self get_cmd_xy:i :&x :&y];
		[citem[i] setPosition:ccp(x, y)];
		[menu addChild:citem[i]];
	}
	[menu setPosition:ccp(470, 60)];
	[self addChild:menu z:2];	
}

- (void)initKeyboard {
	int x, y, i;
	
	keypad = [Sprite spriteWithFile:@"keypad.png"];
	[keypad setRelativeTransformAnchor:NO];
	[keypad setPosition:ccp(1000,1000)];
	keypad.visible = NO;
	[self addChild:keypad z:2];
	
	kmenu = [Menu menuWithItems:nil];
	for(i = 0 ; i < 10 ; i ++) {
		NSString *str2 = @"W";
		
		kitem[i] = [MenuItemFont itemFromString:str2 target:self selector:@selector(keyboardClicked:)];
		Label *label = kitem[i].label;
		if(i < 9)
			[label initWithString:str2 dimensions:CGSizeMake(40,30) alignment:UITextAlignmentCenter fontName:@"Helvetica" fontSize:24];
		else
			[label initWithString:str2 dimensions:CGSizeMake(120,30) alignment:UITextAlignmentCenter fontName:@"Helvetica" fontSize:24];
			
		[label setRGB:0 :0 :0x80];
		
		[self get_keyboard_xy:i :&x :&y];
		[kitem[i] setPosition:ccp(x, y)];
		[kmenu addChild:kitem[i]];
		
		char c;
		if([self is_alpha_doku])
			c = 'A';
		else
			c = '1';
		
		NSString *str;
		if(i < 9)
			str = [[NSString alloc] initWithFormat:@"%c", c+i];
		else
			str = [[NSString alloc] initWithFormat:@"c"];
		
		[kitem[i] setString:str];
	}
	
	[kmenu setRelativeTransformAnchor:NO];
	[kmenu setPosition:ccp(1000, 1000)];
	kmenu.visible = NO;
	
	[keypad setOpacity:210];
	[kmenu setOpacity:210];
	
	[self addChild:kmenu z:3];	
}

- (void)updateKeyboard {
	int i;
	
	for(i = 0 ; i < 9 ; i ++) {
		char c;
	
		if([self is_alpha_doku])
			c = 'A';
		else
			c = '1';
	
		NSString *str = [[NSString alloc] initWithFormat:@"%c", c+i];

		[kitem[i] setString:str];
	}
}

- (void)initLevel {
	question = [Question new];
	level = 1;
	
	cur_question = [question get:level-1];
	if(cur_question == nil || strlen(cur_question) != 82) {
		cur_question = nil;
		return;
	}

	NSString *levelString = [[NSString alloc] initWithFormat:@"Level %3d", level];
	levelLabel = [Label labelWithString:levelString fontName:@"Marker Felt" fontSize:11];
	[levelLabel setPosition:ccp(400, 309)];

	if([question finished:level-1])
		[levelLabel setRGB:GAME_FINISH_R :GAME_FINISH_G :GAME_FINISH_B];
	else {
		char difficulty = '0';
		difficulty = cur_question[0];
		
		switch (difficulty) {
			case '1':
				[levelLabel setRGB:GAME_EASY_R :GAME_EASY_G :GAME_EASY_B];
				break;
			case '2':
				[levelLabel setRGB:GAME_MEDIUM_R :GAME_MEDIUM_G :GAME_MEDIUM_B];
				break;
			case '3':
				[levelLabel setRGB:GAME_HARD_R :GAME_HARD_G :GAME_HARD_B];
				break;
			case '4':
				[levelLabel setRGB:GAME_EVIL_R :GAME_EVIL_G :GAME_EVIL_B];
				break;
			case '0':
				[levelLabel setRGB:0 :0 :0];
				break;
			default:
				break;
		}
	}
	
	[self addChild:levelLabel z:0];
}

- (void)updateLevel {
	NSString *levelString = [[NSString alloc] initWithFormat:@"Level %3d", level];
	[levelLabel setString:levelString];
	if([question finished:level-1])
		[levelLabel setRGB:GAME_FINISH_R :GAME_FINISH_G :GAME_FINISH_B];
	else {
		char difficulty = '0';
		difficulty = cur_question[0];
	
		switch (difficulty) {
			case '1':
				[levelLabel setRGB:GAME_EASY_R :GAME_EASY_G :GAME_EASY_B];
				break;
			case '2':
				[levelLabel setRGB:GAME_MEDIUM_R :GAME_MEDIUM_G :GAME_MEDIUM_B];
				break;
			case '3':
				[levelLabel setRGB:GAME_HARD_R :GAME_HARD_G :GAME_HARD_B];
				break;
			case '4':
				[levelLabel setRGB:GAME_EVIL_R :GAME_EVIL_G :GAME_EVIL_B];
				break;
			case '0':
				[levelLabel setRGB:0 :0 :0];
				break;
			default:
				break;
		}
	}
}

- (void)initTime {
	begin_time = time(NULL);
	cur_times = 0;
	
	NSString *timeString = [[NSString alloc] initWithFormat:@"000  min"];
	timeLabel = [Label labelWithString:timeString fontName:@"Marker Felt" fontSize:11];
	[timeLabel setPosition:ccp(346, 200)];
	[timeLabel setRGB:0 :0 :0x80];
	[self addChild:timeLabel z:0];
}

- (void)updateTime {
	int t;
	
	t = (time(NULL) - begin_time) / 60;
	if(t < 0)
		t = 0;
	if(t > 999)
		t = 999;

	if(t != cur_times) {
		NSString *timeString = [[NSString alloc] initWithFormat:@"%03d  min", t];
		[timeLabel setString:timeString];
		cur_times = t;
	}
}

- (void)update:(ccTime)dt {
	[self updateTime];
}

- (void)resetTime {
	NSString *timeString = [[NSString alloc] initWithFormat:@"000  min"];
	[timeLabel setString:timeString];
	begin_time = time(NULL);
	cur_times = 0;
}

- (void)initDifficulty {
	int i;
	for(i = 0 ; i < 4 ; i ++) {
		hardSprite[i] = [Sprite spriteWithFile:@"dot1.png"];
		[hardSprite[i] setPosition:ccp(330 + i * 11, 220)];
		[self addChild:hardSprite[i] z:0];
		hardSprite[i].visible = NO;

		easySprite[i] = [Sprite spriteWithFile:@"dot2.png"];
		[easySprite[i] setPosition:ccp(330 + i * 11, 220)];
		[self addChild:easySprite[i] z:0];
		easySprite[i].visible = NO;
	}

	[self updateDifficulty];
}

- (void)updateDifficulty {
	int difficulty = cur_question[0] - '0';
	int i;
	
	if(difficulty < 0)
		difficulty = 0;
	if(difficulty > 4)
		difficulty = 4;
	
	for(i = 0 ; i < difficulty ; i ++) {
		hardSprite[i].visible = YES;
		easySprite[i].visible = NO;
	}
	
	for( ; i < 4 ; i ++) {
		hardSprite[i].visible = NO;
		easySprite[i].visible = YES;
	}
}

- (void)initBoard {
	char c;
	int x, y, i;
	
	Menu *menu = [Menu menuWithItems:nil];	
	
	for(i = 0 ; i < 81 ; i ++) {
		c = [self get_digit:i];
		if(c == '0')
			c = ' ';
		
		if(c >= 'a' && c <= 'z')
			c = c - 'a' + 'A';

		NSString *str = [[NSString alloc] initWithFormat:@"%c", c];
		NSString *str2 = @"W";
		
		if(c == ' ') {
			ditem[i] = [MenuItemFont itemFromString:str2 target:self selector:@selector(digitClicked:)];
			Label *label = ditem[i].label;
			[label initWithString:str dimensions:CGSizeMake(30,30) alignment:UITextAlignmentCenter fontName:@"Marker Felt" fontSize:26];
			[label setRGB:207 :119 :179];
			[ditem[i] setString:str];
			board[i/9][i%9] = 0;
		} else {
			ditem[i] = [MenuItemFont itemFromString:str2 target:self selector:@selector(digitClicked:)];
			Label *label = ditem[i].label;
			[label initWithString:str dimensions:CGSizeMake(30,30) alignment:UITextAlignmentCenter fontName:@"Marker Felt" fontSize:26];
			[label setRGB:0 :0 :0];
			[ditem[i] setString:str];
			
			if(c >= 'A' && c <= 'Z')
				board[i/9][i%9] = c - 'A' + 1;
			else
				board[i/9][i%9] = c - '0';
		}
		
		[self get_digit_xy:i :&x :&y];
		[ditem[i] setPosition:ccp(x, y)];
		[menu addChild:ditem[i]];
	}
	
	[menu setPosition:ccp(0, 0)];
	[self addChild:menu z:0];
}

- (void)updateBoard {
	char c;
	int i;
	
	for(i = 0 ; i < 81 ; i ++) {
		c = [self get_digit:i];
		if(c == '0')
			c = ' ';
		if(c >= 'a' && c <= 'z')
			c = c - 'a' + 'A';
		
		NSString *str = [[NSString alloc] initWithFormat:@"%c", c];
		
		if(c == ' ') {
			[ditem[i] setString:str];
			board[i/9][i%9] = 0;
		} else {
			[ditem[i] setString:str];
			if(c >= 'a' && c <= 'z')
				board[i/9][i%9] = c - 'a' + 1;
			else if(c >= 'A' && c <= 'Z')
				board[i/9][i%9] = c - 'A' + 1;
			else
				board[i/9][i%9] = c - '0';
			[ditem[i].label setRGB:0 :0 :0];
		}		
	}
}

-(void)playNextSound
{
	NSString *path = [[NSBundle mainBundle] pathForResource:@"next" ofType:@"wav"];
	SystemSoundID soundID;
	AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:path], &soundID);
	AudioServicesPlaySystemSound (soundID);	
}

-(void)playEndSound
{
	NSString *path = [[NSBundle mainBundle] pathForResource:@"end" ofType:@"wav"];
	SystemSoundID soundID;
	AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:path], &soundID);
	AudioServicesPlaySystemSound (soundID);	
}

- (id)init {
	NSLog(@"GameLayer init");
	self = [super init];
	if(self != nil) {
		[self initKeyboard];
		[self initCmd];
		[self initLevel];
		
		if(cur_question) {
			[self initTime];
			[self initDifficulty];
			[self initBoard];
			[self schedule:@selector(update:) interval:1];
		}
	}
	return self;
}

- (void)dealloc {
	NSLog(@"GameLayer dealloc");
	[question release];
	[super dealloc];
}

/*
- (void)startGame:(id)sender {
	GameScene *gs = [GameScene node];
	[[Director sharedDirector] replaceScene:gs];
	NSLog(@"start game");
}
*/

- (int)nextGame {
	NSLog(@"next game");
	
	level ++;
	
	if(level > MAX_GAMES) {
		MenuScene *ms = [MenuScene node];
		[[Director sharedDirector] replaceScene:ms];
		return -1;
	}
	cur_question = [question get:level-1];
	if(cur_question == nil || strlen(cur_question) != 82) {
		MenuScene *ms = [MenuScene node];
		[[Director sharedDirector] replaceScene:ms];
		return -1;
	}
	
	[self updateLevel];
	[self updateBoard];
	[self resetTime];
	[self updateDifficulty];
	[self updateKeyboard];	
	[self schedule:@selector(update:)];
	return 0;
}

- (void)mainGame {
	NSLog(@"main game");
	
	MenuScene *ms = [MenuScene node];
	[[Director sharedDirector] replaceScene:ms];
	return;	
}

- (void)fillByHint:(char [9][9])myBoard {
	NSString *str;
	bool bExist;
	int i, j;
	char c;
	
	for(i = 0 ; i < 9 ; i ++)
		for(j = 0 ; j < 9 ; j ++) {
			if(board[i][j])
				continue;
			
			if(! myBoard[i][j])
				continue;
			
			board[i][j] = myBoard[i][j];

			if([self is_alpha_doku])
				c = 'A' - 1;
			else
				c = '0';
			
			str = [[NSString alloc] initWithFormat:@"%c", c+myBoard[i][j]];
			[ditem[i*9+j] setString:str];
			
			bExist = [self isExisted:i :j :board];
			if(bExist)
				[ditem[i*9+j].label setRGB:0xcc :0x00 :0x00];
			else
				[ditem[i*9+j].label setRGB:43 :0 :233];
			
		}			
}

- (void)hintGame {
	NSLog(@"hint game");
	
	char myBoard[9][9];
	int ret;
	
	ret = [question robot:board :&myBoard];
	if(ret)
		return;
	[self fillByHint:myBoard];
}

- (void)prevGame {
	NSLog(@"prev game");
	
	if(level <= 1)
		return;
	
	level --;
	
	cur_question = [question get:level-1];
	if(cur_question == nil || strlen(cur_question) != 82) {
		MenuScene *ms = [MenuScene node];
		[[Director sharedDirector] replaceScene:ms];
		return;
	}
	
	[self updateLevel];
	[self updateBoard];
	[self resetTime];
	[self updateDifficulty];
	[self updateKeyboard];
	[self schedule:@selector(update:)];
}

- (int)resetGame {
	NSLog(@"reset game");
	
	if(level < 1) {
		MenuScene *ms = [MenuScene node];
		[[Director sharedDirector] replaceScene:ms];
		return -1;
	}
	
	cur_question = [question get:level-1];
	if(cur_question == nil || strlen(cur_question) != 82) {
		MenuScene *ms = [MenuScene node];
		[[Director sharedDirector] replaceScene:ms];
		return -1;
	}
	
	[self updateBoard];
	[self resetTime];
	[self schedule:@selector(update:)];
	return 0;
}

- (void)levelGame {
	NSLog(@"level game");
	LevelScene *ls = [LevelScene node];
	[[Director sharedDirector] replaceScene:ls];	
}

- (void)setLevel:(int)lv {
	level = lv;
	
	if([self resetGame] < 0)
		return;
	
	[self updateLevel];
	[self updateDifficulty];
	[self updateKeyboard];
}

- (void)digitClicked:(id)sender {
	if(kmenu.visible == YES)
		return;
	
	for(dindex = 80 ; dindex >= 0 ; dindex --)
		if(ditem[dindex] == sender)
			break;

	if(dindex < 0)
		return;
	
	if(cur_question == nil)
		return;
	
	if(cur_question[1+dindex] != '0' && cur_question[1+dindex] != ' ')
		return;
	
	NSLog(@"digit item %d clicked", dindex);

	int x, y;
	int keypad_x, keypad_y;
	int max_x = 320, max_y = 320;
	
	keypad_x = [keypad contentSize].width / 2;
	keypad_y = [keypad contentSize].height / 2;
	[self get_digit_xy:dindex :&x :&y];
	
	x -= keypad_x;
	y -= (keypad_y + 15);
	
	if(x < 0)
		x = 0;
	if(y < 0)
		y = 0;
	if(x > max_x - 2 * keypad_x)
		x = max_x - 2 * keypad_x;
	if(y > max_y - 2 * keypad_y)
		y = max_y - 2 * keypad_y;

	[keypad runAction:[MoveTo actionWithDuration:0 position:ccp(x,y)]];
	[kmenu runAction:[MoveTo actionWithDuration:0 position:ccp(x,y)]];
	keypad.visible = YES;
	kmenu.visible = YES;
}

- (bool)isExisted:(int)i :(int)j :(char [9][9])myBoard {
	int k;
	int l;
	
	for(k = 0 ; k < 9 ; k ++)
		if(k != j && myBoard[i][k] == myBoard[i][j])
			return YES;
	
	for(k = 0 ; k < 9 ; k ++)
		if(k != i && myBoard[k][j] == myBoard[i][j])
			return YES;
	
	for(k = (i / 3) * 3 ; k < (i / 3) * 3 + 3 ; k ++)
		for(l = (j / 3) * 3 ; l < (j / 3) * 3 + 3 ; l ++)
			if(k != i && l != j && myBoard[k][l] == myBoard[i][j])
				return YES;
	
	return NO;
}

- (bool)isFull:(char [9][9]) myBoard {
	int i, j;
	
	for(i = 0 ; i < 9 ; i ++)
		for(j = 0 ; j < 9 ; j ++)
			if(myBoard[i][j] == 0)
				return NO;
	
	return YES;
}

- (bool)isWin {
	int i, j;
	for(i = 0 ; i < 9 ; i ++)
		for(j = 0 ; j < 9 ; j ++)
			if([self isExisted:i :j :board])
				return NO;
	return YES;
}

- (void)keyboardClicked:(id)sender {
	int i;
	
	for(i = 9 ; i >= 0 ; i --)
		if(kitem[i] == sender)
			break;
	if(i < 0)
		return;
	
	NSLog(@"keyboard item %d clicked", i);
	
	if(dindex < 0 || dindex > 80)
		return;
	
	int x, y;
	x = 1000;
	y = 1000;
	keypad.visible = NO;
	kmenu.visible = NO;
	[keypad runAction:[MoveTo actionWithDuration:0 position:ccp(x,y)]];
	[kmenu runAction:[MoveTo actionWithDuration:0 position:ccp(x,y)]];
	
	char c;
	if([self is_alpha_doku])
		c = 'A';
	else
		c = '1';
	
	NSString *str;
	if(i < 9)
		str = [[NSString alloc] initWithFormat:@"%c", c+i];
	else
		str = [[NSString alloc] initWithFormat:@" "];
	
	[ditem[dindex] setString:str];
	
	if(i < 9) {
		board[dindex/9][dindex%9] = i + 1;
	
		bool bExist = [self isExisted:dindex/9 :dindex%9 :board];
		if(bExist)
			[ditem[dindex].label setRGB:0xcc :0x00 :0x00];
		else
			[ditem[dindex].label setRGB:43 :0 :233];
	} else
		board[dindex/9][dindex%9] = 0;
	
	bool isFull = [self isFull:board];
	if(isFull) {
		if([self isWin]) {
			[self unschedule:@selector(update:)];
			[question finish:level-1];
			NSLog(@"You win!");
			int ret = [self nextGame];
			if(ret == 0)
				[self playNextSound];
			else
				[self playEndSound];
		}
	}
}

- (void)cmdClicked:(id)sender {
	int i;
	
	for(i = 5 ; i >= 0 ; i --)
		if(citem[i] == sender)
			break;
	if(i < 0)
		return;
	
	NSLog(@"cmd item #%d Clicked", i);
	
	switch(i) {
	case 0:
		[self unschedule:@selector(update:)];
		[self nextGame];
		break;
	case 1:
		[self unschedule:@selector(update:)];
		[self prevGame];
		break;
	case 2:
		[self levelGame];
		break;
	case 3:
		[self unschedule:@selector(update:)];
		[self resetGame];
		break;
	case 4:
		[self hintGame];
		break;
	case 5:
		[self unschedule:@selector(update:)];
		[self mainGame];
		break;
	}
}

@end